package com.yps.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import com.yps.util.Calculator;


/**
 * NIO服务端
 * @author yps
 *
 */
public class ServerHandle implements Runnable {
	
	private Selector selector;
	private ServerSocketChannel serverChannel;
	private volatile boolean started;
	
	
	/**
	 * 带参数构造方法
	 * @param port 监听端口
	 */
	public ServerHandle(int port) {
		try {
			//创建选择器
			selector = Selector.open();
			//打开监听通道
			serverChannel = ServerSocketChannel.open();
			//因为NIO是同步非阻塞， 设置为false
			serverChannel.configureBlocking(false);
			//绑定端口 backlog设置为1024
			serverChannel.socket().bind(new InetSocketAddress(port),1024);
			//注册选择器selector ，监听客户端请求,设置为监听
			serverChannel.register(selector, SelectionKey.OP_ACCEPT);
			//标记服务器开启
			started = true;
			System.out.println("服务器已经启动，端口号：" + port);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	@Override
	public void run() {
		while (started) {
			try {
				//无论是否发生读写事件，selector每个1s被唤醒一次
				selector.select(1000);
				//阻塞， 只有当至少一个注册的事件发生的时候才会继续、
				//selector.select();
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> it = keys.iterator();
				SelectionKey key = null;
				while (it.hasNext()) {
					key = (SelectionKey) it.next();
					it.remove();
					try {
						handleInput(key);//值传入处理方法
					} catch (Exception e) {
						if(key != null){
							key.cancel();
							if(key.channel() != null)
								key.channel().close();
						}
					}
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if(selector != null){
			try {
				selector.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void handleInput(SelectionKey key) throws IOException {
		if(key.isValid()){//有效的key
			//处理新接入的请求消息
			if(key.isAcceptable()){
				ServerSocketChannel ssc  = (ServerSocketChannel) key.channel();
				//通过serverSocketChannel的accept穿件SocketChannel的实例
				// 完成该操作表示完成了TCP三次握手
				SocketChannel sc = ssc.accept();
				//设置为非阻塞
				sc.configureBlocking(false);
				//注册为读
				sc.register(selector, SelectionKey.OP_READ);
			}
			if(key.isReadable()){//可读
				SocketChannel sc = (SocketChannel) key.channel();
				//创建ByteBuffer 并且开辟一个1m的缓冲区
				ByteBuffer buffer = ByteBuffer.allocate(1024);
				//读取请求吗流，并且返回读取的字节数
				int readBytes = sc.read(buffer);
				if(readBytes > 0){
					//将缓冲区当前的limit设置为position = 0, 用于后续对缓冲区的读取操作
					buffer.flip();
					//根据缓冲区可读字节数穿件字节数组
					byte[] bytes = new byte[buffer.remaining()];
					//将buff缓冲区可读字节数组复制到新建的数组中
					buffer.get(bytes);
					String expression = new String(bytes,"UTF-8");
					//处理数据
					System.out.println("服务端收到消息："+expression);
					String result = null;
					try {
						result = Calculator.cal(expression).toString();
					} catch (Exception e) {
						result = "计算错误: " + e.getMessage(); 
					}
					//回复应答消息
					doWrite(sc,result);
				}else if(readBytes < 0){//关闭资源
					key.cancel();
					sc.close();
				}
			}
		}
	}

	private void doWrite(SocketChannel channel, String response) throws IOException {
		//将消息编码为字节数组
		byte[] bytes = response.getBytes();
		//创建数组容量的ByteBuffer
		ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
		//将字节数组复制到缓存区
		writeBuffer.put(bytes);
		//filp操作
		writeBuffer.flip();
		//发送缓冲区字节数组
		channel.write(writeBuffer);
	}

	public void stop() {
		started = false;
	}

}
